

class Link_Creator

  attr_accessor :active_links
  attr_accessor :boundary_loop_links
  attr_accessor :active_to_boundary_links
  attr_accessor :all_active_controllers
  attr_accessor :all_boundary_controllers
  attr_accessor :active_controller_links_list
  attr_accessor :boundary_controller_links_list
  attr_accessor :column_length
  attr_accessor :row_length

  def initialize ( x , y )

    @column_length = x
    @row_length = y

    @active_links = Array.new
    @boundary_loop_links = Array.new
    @active_to_boundary_links = Array.new
    @all_controller_list = Array.new
    @all_active_controllers = Array.new
    @all_boundary_controllers = Array.new
    @active_controller_links_list = Array.new
    @boundary_controller_links_list = Array.new

    createActiveLinkNames()
    createBoundaryLoopLinks()
    createActiveToBoundaryLinks()
    getAllActiveControllersLinks()
    getAllBoundaryControllersLinks()

  end

  def printMatrix

    for row in (1..@row_length)

      for column in (1..@column_length)

        print( ( column + ( @column_length * ( row - 1) ) ) )
        print(" ")

      end

      print("\n")

    end

  end

  def createListOfActiveControllers

    for row in (1..@row_length)

      for column in (1..@column_length)

        @all_active_controllers.push( (column + ( ( row - 1 ) * @column_length ) ).to_s() )

      end

    end

  end

  def createListOfBoundaryControllers

    for counter in (0..( @column_length + ( ( @row_length + 1 ) * 2 ) + @column_length + 1 ))

      @all_boundary_controllers.push( "b#{counter}" )

    end

  end

  def createActiveToBoundaryLinks

    boundary_slot = 0

    # top row
    for column in (1..@column_length)

      if ( column == 1 )

        westBoundary = (@column_length + 2)
        southWestBoundary = (westBoundary + 2)

        insertActiveToBoundaryLink( westBoundary, column )
        insertActiveToBoundaryLink( southWestBoundary, column )

      end

      if ( column == @column_length )

        eastBoundary = westBoundary + 1
        southEastBoundary = westBoundary + 3

        insertActiveToBoundaryLink( eastBoundary, column )
        insertActiveToBoundaryLink( southEastBoundary, column )

      end

      # north east
      insertActiveToBoundaryLink( column - 1, column )
      # north
      insertActiveToBoundaryLink( column    , column )
      # north west
      insertActiveToBoundaryLink( column + 1, column )

    end

    # middle rows on the side
    for row in (1..@row_length)

      if ( row != 1 and row != @row_length )

        # left is (x2)
        northWestBoundary = ( ( row - 1 ) * 2 ) + @column_length
        westBoundary = (row * 2 ) + @column_length
        southWestBoundary = ( ( row + 1 ) * 2 ) + @column_length

        linkNumber = ( ( row  - 1 ) * @column_length ) + 1

        insertActiveToBoundaryLink( northWestBoundary, linkNumber )
        insertActiveToBoundaryLink( westBoundary, linkNumber )
        insertActiveToBoundaryLink( southWestBoundary, linkNumber )

        # right is (x2) + 1
        northEastBoundary = ( ( row - 1 ) * 2 ) + @column_length + 1
        eastBoundary = (row * 2 ) + @column_length + 1
        southEastBoundary = ( ( row + 1 ) * 2 ) + @column_length + 1

        linkNumber = ( ( row  - 1 ) * @column_length ) + @column_length

        insertActiveToBoundaryLink( northEastBoundary, linkNumber )
        insertActiveToBoundaryLink( eastBoundary, linkNumber )
        insertActiveToBoundaryLink( southEastBoundary, linkNumber )

      end

    end

    # bottom row
    for column in (1..@column_length)

      linkNumber = ( @row_length * ( @column_length - 1 ) )  + column

      if ( column == 1 )

        westBoundary = ( @column_length + ( @row_length * 2 ) )
        northWestBoundary = ( @column_length + ( ( @row_length - 1 ) * 2 ) )

        insertActiveToBoundaryLink( westBoundary, linkNumber )
        insertActiveToBoundaryLink( northWestBoundary, linkNumber )

      end

      if ( column == @column_length )

        eastBoundary = ( @column_length + ( @row_length * 2 ) ) + 1
        northEastBoundary = ( @column_length + ( ( @row_length - 1 ) * 2 ) ) + 1

        insertActiveToBoundaryLink( eastBoundary, linkNumber )
        insertActiveToBoundaryLink( northEastBoundary, linkNumber )

      end

      southEastBoundary = @column_length + ( ( @row_length + 1 ) * 2 ) + column + 1
      southBoundary = @column_length + ( ( @row_length + 1 ) * 2 ) + column 
      southWestBoundary = @column_length + ( ( @row_length + 1 ) * 2 ) + column - 1

      insertActiveToBoundaryLink( southEastBoundary, linkNumber )
      insertActiveToBoundaryLink( southBoundary, linkNumber )
      insertActiveToBoundaryLink( southWestBoundary, linkNumber )

    end

  end

  def createBoundaryLoopLinks

    boundary_slot = 0
    direction_array = Array.new

    insertBoundaryloopLinks( boundary_slot, ["n","ne","nw","s","sw","e","w"] )
    boundary_slot = boundary_slot + 1

    for column in (1..@column_length)

      if ( column == 1 )
        direction_array.push("sw")
      end

      if ( column == @column_length )
        direction_array.push("se")
      end

      # normal loops for top row
      direction_array.push("n")
      direction_array.push("ne")
      direction_array.push("nw")
      direction_array.push("e")
      direction_array.push("w")

      # insert into loop array
      insertBoundaryloopLinks(boundary_slot, direction_array)

      # increment counter
      boundary_slot = boundary_slot + 1
      
      direction_array.clear()
    end

    # create corners
    insertBoundaryloopLinks( boundary_slot, ["n","ne","nw","s","se","e","w"] )
    boundary_slot = boundary_slot + 1

    for row in (1..@row_length)

      # do left side of matrix boundary
      if ( row == 1 )
        direction_array.push("ne")
      end

      if ( row == @row_length )
        direction_array.push("se")
      end

      direction_array.push("n")
      direction_array.push("nw")
      direction_array.push("s")
      direction_array.push("sw")
      direction_array.push("w")

      insertBoundaryloopLinks( boundary_slot, direction_array )
      boundary_slot = boundary_slot + 1

      direction_array.clear()

      # do right side of matrix boundary
      if ( row == 1 )
        direction_array.push("nw")
      end

      if ( row == @row_length )
        direction_array.push("sw")
      end

      direction_array.push("n")
      direction_array.push("ne")
      direction_array.push("s")
      direction_array.push("se")
      direction_array.push("e")

      insertBoundaryloopLinks( boundary_slot, direction_array )
      boundary_slot = boundary_slot + 1

      direction_array.clear()

    end 
    
    insertBoundaryloopLinks( boundary_slot, ["n","nw","s","se","sw","e","w"] )
    boundary_slot = boundary_slot + 1

    # bottom row
    for column in (1..@column_length)

      if ( column == 1 )
        direction_array.push("nw")
      end

      if ( column == @column_length )
        direction_array.push("ne")
      end

      # normal loops for top row
      direction_array.push("s")
      direction_array.push("se")
      direction_array.push("sw")
      direction_array.push("e")
      direction_array.push("w")

      # insert into loop array
      insertBoundaryloopLinks(boundary_slot, direction_array)

      # increment counter
      boundary_slot = boundary_slot + 1
      
      direction_array.clear()

    end
    
    insertBoundaryloopLinks( boundary_slot, ["n","ne","s","sw","se","e","w"] )

  end

  def createActiveLinkNames

    for row in (1..@row_length)

      for column in (1..@column_length)

        getActiveWest( column + ( @column_length * ( row - 1) ) )
        getActiveSouthWest( column + ( @column_length * ( row - 1) ) )
        getActiveNorthWest( column + ( @column_length * ( row - 1) ) )
        getActiveSouth( column + ( @column_length * ( row - 1) ) )

      end

    end

  end

  def insertActiveLink( start, finish )

    if ( nil == @active_links.index( start.to_s() + "_" + finish.to_s() ) )

        @active_links.push( start.to_s() + "_" + finish.to_s() )

    end

  end

  def insertBoundaryloopLinks( link, direction )
    
    direction.each { |direction_name|

      if ( nil == @boundary_loop_links.index( "b" + link.to_s() + "_" + direction_name ) )

        @boundary_loop_links.push( "b" + link.to_s() + "_" + direction_name )

      end

    }

  end

  def insertActiveToBoundaryLink( boundary, link )

    if ( nil == @active_to_boundary_links.index( link.to_s() + "_b" + boundary.to_s() ) )

      @active_to_boundary_links.push( link.to_s() + "_b" + boundary.to_s() )

    end

  end

  def getActiveControllerNorthLink( controller )

    # top row
    if ( controller <= @column_length )
      return "physical_link_#{controller}_b#{controller}"
    end

    if ( controller > @column_length )
      divmod_result = controller.divmod( @column_length )
      north_link = ( ( divmod_result[0]  - 1 ) * @column_length ) + divmod_result[1]
      return "physical_link_#{controller}_#{north_link}"
    end

  end

  def getActiveControllerNorthEastLink( controller )

    if ( controller <= @column_length )
      return "physical_link_#{controller}_b#{controller + 1}"
    end

    # not on east edge
    if ( controller > @column_length and ( controller.modulo( @column_length ) != 0 ) )
      divmod_result = controller.divmod( @column_length )
      link_ref = ( ( divmod_result[0]  - 1 ) * @column_length ) + divmod_result[1]
      return "physical_link_#{controller}_#{link_ref + 1}"
    end

    # on east edge
    if ( controller > @column_length and ( controller.modulo( @column_length ) == 0 ) )
      divmod_result = controller.divmod( @column_length )
      # looks different because this results on the carry over
      link_ref = ( ( divmod_result[0] - 1 ) * 2 ) + @column_length + 1
      return "physical_link_#{controller}_b#{link_ref}"
    end

  end

  def getActiveControllerNorthWestLink( controller )

    if ( controller <= @column_length )
      return "physical_link_#{controller}_b#{controller - 1}"
    end

    # not on west edge
    if ( controller > @column_length and ( controller.modulo( @column_length ) != 1 ) )
      divmod_result = controller.divmod( @column_length )
      link_ref = ( ( divmod_result[0]  - 1 ) * @column_length ) + divmod_result[1]
      return "physical_link_#{controller}_#{link_ref - 1}"
    end

    # on west edge
    if ( controller > @column_length and ( controller.modulo( @column_length ) == 1 ) )
      divmod_result = controller.divmod( @column_length )
      link_ref = ( ( divmod_result[0] ) * 2 ) + @column_length 
      return "physical_link_#{controller}_b#{link_ref}"
    end

  end

  def getActiveControllerSouthLink( controller )

    if ( controller > ( @column_length * ( @row_length - 1 ) ) )
      divmod_result = controller.modulo( @column_length )

      if ( divmod_result == 0 )
        divmod_result = @column_length
      end
      
      link_ref = ( @column_length + ( ( @row_length + 1 ) * 2 ) + divmod_result )
      return "physical_link_#{controller}_b#{link_ref}"
    end

    if ( controller <= ( @column_length * ( @row_length - 1 ) ) )

      return "physical_link_#{controller}_#{controller + @column_length}"

    end

  end

  def getActiveControllerSouthEastLink( controller )

    if ( controller > ( @column_length * ( @row_length - 1 ) ) )
      divmod_result = controller.modulo( @column_length )

      if ( divmod_result == 0 )
        divmod_result = @column_length
      end
      
      link_ref = ( @column_length + ( ( @row_length + 1 ) * 2 ) + divmod_result )
      return "physical_link_#{controller}_b#{link_ref + 1}"
    end

    # not on east edge
    if ( controller.modulo( @column_length ) != 0 )
      link_ref = controller + @column_length
      return "physical_link_#{controller}_#{link_ref + 1}"
    end

    # on east edge
    if ( controller.modulo( @column_length ) == 0 )
      divmod_result = controller.divmod( @column_length )
      # looks different because this results on the carry over
      link_ref = @column_length + ( ( divmod_result[0] + 1 ) * 2 ) + 1 
      return "physical_link_#{controller}_b#{link_ref}"
    end
  end

  def getActiveControllerSouthWestLink( controller )

    if ( controller > ( @column_length * ( @row_length - 1 ) ) )
      divmod_result = controller.modulo( @column_length )

      if ( divmod_result == 0 )
        divmod_result = @column_length
      end
      
      link_ref = ( @column_length + ( ( @row_length + 1 ) * 2 ) + divmod_result )
      return "physical_link_#{controller}_b#{link_ref - 1}"
    end

    # not on west edge
    if ( controller.modulo( @column_length ) != 1 )
      link_ref = controller + @column_length
      return "physical_link_#{controller}_#{link_ref - 1}"
    end

    # on west edge
    if ( controller.modulo( @column_length ) == 1 )
      divmod_result = controller.divmod( @column_length )
      # looks different because this results on the carry over
      link_ref = @column_length + ( ( divmod_result[0] + 2 ) * 2 ) 
      return "physical_link_#{controller}_b#{link_ref}"
    end

  end

  def getActiveControllerEastLink( controller )

    if ( controller.modulo( @column_length ) != 0 )
      return "physical_link_#{controller}_#{controller + 1}"
    end

    if ( controller.modulo( @column_length ) == 0 )
      link_ref = @column_length + ( ( controller.div( @column_length ) ) * 2 ) + 1 
      return "physical_link_#{controller}_b#{link_ref}"
    end

  end

  def getActiveControllerWestLink( controller )

    if ( controller.modulo( @column_length ) != 1 )
      return "physical_link_#{controller}_#{controller - 1}"
    end

    if ( controller.modulo( @column_length ) == 1 )
      link_ref = @column_length + ( ( controller.div( @column_length ) + 1 ) * 2 )
      return "physical_link_#{controller}_b#{link_ref}"
    end

  end

  def getAllActiveControllersLinks

    createListOfActiveControllers()

    links_list = Array.new

    for controller in all_active_controllers

      links_list.push controller
      links_list.push getActiveControllerNorthLink( controller.to_i() )
      links_list.push getActiveControllerNorthEastLink( controller.to_i() )
      links_list.push getActiveControllerNorthWestLink( controller.to_i() )
      links_list.push getActiveControllerSouthLink( controller.to_i() )
      links_list.push getActiveControllerSouthEastLink( controller.to_i() )
      links_list.push getActiveControllerSouthWestLink( controller.to_i() )
      links_list.push getActiveControllerEastLink( controller.to_i() )
      links_list.push getActiveControllerWestLink( controller.to_i() )

      @active_controller_links_list.push(Array.new(links_list))

      links_list.clear

    end

  end

  def getBoundaryControllerNorthLink( controller )

    if ( controller >= @column_length + ( ( @row_length + 1 ) * 2 ) + 1 and
        controller <= @column_length + ( ( @row_length + 1 ) * 2 ) + @column_length )
      link_ref = controller - ( @column_length + ( ( @row_length + 1 ) * 2 ) )
      link_ref = link_ref + @column_length * ( @row_length - 1 )
      return  "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_n"
    end

  end

  def getBoundaryControllerNorthEastLink( controller )

    # bottom row
    if ( controller >= @column_length + ( ( @row_length + 1 ) * 2 ) and
        controller <= @column_length + ( ( @row_length + 1 ) * 2 ) + @column_length - 1 )
      link_ref = controller - ( @column_length + ( ( @row_length + 1 ) * 2 ) )
      link_ref = link_ref + @column_length * ( @row_length - 1 )
      return "physical_link_#{link_ref + 1}_b#{controller}"
    # very last processor
    elsif ( controller == ( 2 * @column_length ) + ( ( @row_length + 1 ) * 2 ) + 1 )
      return "p_l_loop_b#{controller}_ne"
    # sides with connect to active processors
    elsif ( controller > (@column_length + 3) and  
           (controller - @column_length).modulo( 2 ) == 0 )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( (link_ref - 2) * @column_length ) + 1
      return "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_ne"
    end

  end

  def getBoundaryControllerNorthWestLink( controller )

    # bottom row
    if ( controller >= @column_length + ( ( @row_length + 1 ) * 2 ) + 2 and
       ( controller <= ( 2 * @column_length ) + ( ( @row_length + 1 ) * 2 ) + 1 ) )
      link_ref = controller - ( @column_length + ( ( @row_length + 1 ) * 2 ) )
      link_ref = link_ref + @column_length * ( @row_length - 1 )
      return "physical_link_#{link_ref - 1}_b#{controller}"
    # east side 
    elsif ( controller > (@column_length + 4) and 
          ( controller - @column_length).modulo( 2 ) == 1 and
          ( controller < @column_length + ( ( @row_length + 1 ) * 2 ) ) )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( ( link_ref - 2 ) * @column_length ) + @column_length
      return "phsical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_nw"
    end

  end

  def getBoundaryControllerSouthLink( controller )

    if ( controller > 0 and controller <= @column_length )
      return "physical_link_#{controller}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_s"
    end

  end

  def getBoundaryControllerSouthEastLink( controller )

    # top row
    if ( controller < @column_length )
      return "physical_link_#{controller + 1}_b#{controller}"
    # west side
    elsif ( controller > ( @column_length + 1 ) and 
            controller < ( @column_length + ( @row_length * 2 ) ) and
          ( controller - @column_length ).modulo( 2 ) == 0 )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( link_ref * @column_length )  + 1
      return "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_se"
    end

  end

  def getBoundaryControllerSouthWestLink( controller )

    # top row
    if ( controller > 1 and controller <= ( @column_length + 1 ) )
      return "physical_link_#{controller - 1 }_b#{controller}"
    # west side
    elsif ( controller > ( @column_length + 1 ) and 
            controller < ( @column_length + ( @row_length * 2 ) ) and
          ( controller - @column_length ).modulo( 2 ) == 1 )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( link_ref * @column_length )  + @column_length
      return "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_sw"
    end

  end

  def getBoundaryControllerEastLink( controller )
    
    # find west side
    if ( controller > ( @column_length + 1 ) and 
         controller < ( @column_length + ( ( @row_length + 1 ) * 2 ) ) and
       ( controller - @column_length ).modulo( 2 ) == 0 )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( ( link_ref - 1 ) * @column_length ) + 1
      return "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_e"
    end

  end

  def getBoundaryControllerWestLink( controller )

    # find west side
    if ( controller > ( @column_length + 1 ) and 
         controller < ( @column_length + ( ( @row_length + 1 ) * 2 ) ) and
       ( controller - @column_length ).modulo( 2 ) == 1 )
      link_ref = ( controller - @column_length ).div( 2 )
      link_ref = ( ( link_ref - 1 ) * @column_length ) + @column_length
      return "physical_link_#{link_ref}_b#{controller}"
    else
      return "p_l_loop_b#{controller}_w"
    end

  end

  def getAllBoundaryControllersLinks

    createListOfBoundaryControllers()

    links_list = Array.new

    for controller in @all_boundary_controllers

      links_list.push controller
      links_list.push getBoundaryControllerNorthLink( controller.sub("b","").to_i() )
      links_list.push getBoundaryControllerNorthEastLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerNorthWestLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerSouthLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerSouthEastLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerSouthWestLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerEastLink( controller.sub("b", "").to_i() )
      links_list.push getBoundaryControllerWestLink( controller.sub("b", "").to_i() )
      
      @boundary_controller_links_list.push(Array.new(links_list))

      links_list.clear

    end

  end





















  # ---------------------------------------------------------------------------
  #
  # helper methods
  #
  # ---------------------------------------------------------------------------

  def getActiveWest( position )

    if ( position.modulo( @row_length ) != 1 ) 

      insertActiveLink( ( position - 1 ), position )

    end

  end

  def getActiveSouthWest( position )

    # not on west edge
    # not on bottom row

    if ( position.modulo( @row_length ) != 1 and
         position < ( ( @row_length * @column_length ) - ( @column_length -1 )  ) )

        insertActiveLink( position, ( @column_length + position - 1 ) )

    end

  end

  def getActiveNorthWest( position )

    # detects if we are on west edge
    if ( position.modulo( @column_length ) != 1 and position > @column_length )

        insertActiveLink( (position - @column_length - 1 ), position ) 

      end

  end

  def getActiveSouth( position )
    
    if ( position.divmod( @column_length )[0] < ( @row_length - 1 )  or 
         ( position.divmod( @column_length )[0] == ( @row_length - 1 ) and
           position.divmod( @column_length )[1] == 0 ) )

      insertActiveLink( position, ( @column_length + position ) )

    end

  end

end
